/**
  ******************************************************************************
  * @file    tm1650.c
  * @author  MCU Application Team
  * @Version V1.0.0
  * @Date    2022-8-19
  * @brief    function
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "tm1650.h"
#include "main.h"

/* Private define ------------------------------------------------------------*/
keybuff_typedef keydata={
    . buff = { 0 },                       //按键发送缓存
    . cnt = 0 ,                           //按键按下计数
    . down_time = 0,                      //按键按下定时
    . time_out_flag = 1,                  //超时标志位
};

/* Private variables ---------------------------------------------------------*/
//往一个指定的数码管位写入指定的显示数据
//共阴数码管段码表：
const uint8_t TUBE_TABLE_0[16] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};    //共阴，0~9~A~F

uint8_t key_value[10] = {0};       //检测到的输入按键

static  uint8_t key_copy = 0;      //记录按键

/* Private function prototypes -----------------------------------------------*/

//产生IIC总线起始信号
static void TM1650_IIC_start(void)
{
    TM1650_IIC_SCL_HIGH;     //SCL=1
    TM1650_IIC_SDA_HIGH;    //SDA=1
    TM1650_IIC_DELAY_4US;
    TM1650_IIC_SDA_LOW;     //SDA=0
    TM1650_IIC_DELAY_4US;
    TM1650_IIC_SCL_LOW;      //SCL=0
}
 
//产生IIC总线结束信号
static void TM1650_IIC_stop(void)
{
    TM1650_IIC_SCL_LOW;      //SCL=0
    TM1650_IIC_SDA_LOW;      //SDA=0
    TM1650_IIC_DELAY_4US;
    TM1650_IIC_SCL_HIGH;     //SCL=1
    TM1650_IIC_DELAY_4US;
    TM1650_IIC_SDA_HIGH;    //SDA=1
}
 
//通过IIC总线发送一个字节
static void TM1650_IIC_write_byte(uint8_t dat)
{
    uint8_t i;
    
    TM1650_IIC_SCL_LOW;
    for(i=0;i<8;i++)
    {
        TM1650_IIC_SDA_WR(dat&0x80);
        dat<<=1;    
        
        TM1650_IIC_DELAY_2US;
        TM1650_IIC_SCL_HIGH;
        TM1650_IIC_DELAY_2US;
        TM1650_IIC_SCL_LOW;
        TM1650_IIC_DELAY_2US;
    }
}
//通过IIC总线接收一个字节
static uint8_t TM1650_IIC_Read_byte(void)
{
    uint8_t buff,i;
    
    TM1650_IIC_SCL_LOW;
    for(i=0;i<8;i++)
    {
        TM1650_IIC_SCL_HIGH;
        TM1650_IIC_DELAY_2US;
        if(TM1650_IIC_SDA_RD())
        {
           buff |= (0x01<<i);
        }else{
           buff &= (~(0x01<<i));
        }
        TM1650_IIC_DELAY_2US;
        TM1650_IIC_SCL_LOW;
        TM1650_IIC_DELAY_2US;
    }
    return  buff;
}

//通过IIC总线接收从机响应的ACK信号
static uint8_t TM1650_IIC_wait_ack(void)
{
    uint8_t ack_signal = 0;
    
    TM1650_IIC_SDA_HIGH;    //SDA=1
    TM1650_IIC_DELAY_2US;
    TM1650_IIC_SCL_HIGH;
    TM1650_IIC_DELAY_2US;
    if(TM1650_IIC_SDA_RD()) ack_signal = 1;   //如果读取到的是NACK信号
    TM1650_IIC_SCL_LOW;
    TM1650_IIC_DELAY_2US;
    return ack_signal;
}

// 通过IIC总线 读取寄存器数据一个字节
uint8_t TM1650_Read_byte(uint8_t addr)
{
    uint8_t read_buff;
    TM1650_IIC_start();
    TM1650_IIC_write_byte(addr);        //寄存器地址
    TM1650_IIC_wait_ack();              //固定命令
    read_buff = TM1650_IIC_Read_byte(); //接收数据
    TM1650_IIC_wait_ack();              
    TM1650_IIC_stop();
    return read_buff;
}

// 通过IIC总线 写入寄存器数据一个字节
void TM1650_Wire_byte(uint8_t addr,uint8_t param)
{
    TM1650_IIC_start();                 //启动
    TM1650_IIC_write_byte(addr);        //写人地址 
    TM1650_IIC_wait_ack();              //固定命令
    TM1650_IIC_write_byte(param);       //写入参数
    TM1650_IIC_wait_ack();              //参数值
    TM1650_IIC_stop();                  //停止
}

//作用：设置显示参数
//备注：这个操作不影响显存中的数据
//用例：
//    设置亮度并打开显示:TM1650_cfg_display(TM1650_BRIGHTx)
//    关闭显示:TM1650_cfg_display(TM1650_DSP_OFF)
void TM1650_cfg_display(uint8_t param)
{
    TM1650_IIC_start();
    TM1650_IIC_write_byte(COMMAND_SET_PARAMETER);  
    TM1650_IIC_wait_ack();     //固定命令
    TM1650_IIC_write_byte(param); 
    TM1650_IIC_wait_ack();    //参数值
    TM1650_IIC_stop();
}
 
 
//将显存数据全部刷为0，清空显示
void TM1650_clear(void)
{
    uint8_t dig;
    for(dig = TM1650_DIG1 ; dig<= TM1650_DIG4 ;dig++)
    {
        TM1650_print(dig,0);   //将显存数据刷为0
    }
}
 
//用例：
//    在DIG1位上显示数字3: TM1650_print(TM1650_DIG1,TUBE_TABLE_0[3]);
void TM1650_print(uint8_t dig,uint8_t seg_data)
{
    TM1650_IIC_start();
    TM1650_IIC_write_byte(dig*2+0x68); //显存起始地址为0x68
    TM1650_IIC_wait_ack();  
    TM1650_IIC_write_byte(seg_data); //发送段码
    TM1650_IIC_wait_ack();    
    TM1650_IIC_stop();
}


// 按键扫描  
uint8_t TM1650_KEY_Scan(void)
{
    uint8_t read_buff;
    TM1650_IIC_start();
    TM1650_IIC_write_byte(0x49);        //读取按键数据命令
    TM1650_IIC_wait_ack();              //固定命令
    read_buff = TM1650_IIC_Read_byte(); //接收数据
    TM1650_IIC_wait_ack();              
    TM1650_IIC_stop();
    return read_buff;
}

//TM1650初始化
void TM1650_init(void)
{
    TM1650_IIC_SCL_MODE_OD;  //SCL开漏输出
    TM1650_IIC_SDA_MODE_OD;  //SDA开漏输出
 
    TM1650_IIC_SDA_HIGH;   //释放SDA线
    TM1650_IIC_SCL_HIGH;   //释放SCL线
    
    LL_mDelay(1000);       //等待上电后，芯片的稳定
    //初始化为 7级亮度，打开显示
    TM1650_cfg_display(PARAMETER_BRIGHTNESS_SEVEN|0x01);
    TM1650_clear();       //将显存内容清0

    key_copy = TM1650_KEY_Scan();  //扫描按键
    
    keydata.sent_flag = 0;
    keydata.down_time = 0;
    keydata.time_out_flag = 1;
    keydata.cnt = 0 ;
    memset(keydata.buff,'0',20);       //清除按键缓存
}

void TM1650_Time_Task(void)
{
  if(keydata.down_time) keydata.down_time--;
   if(keydata.scan_time) keydata.scan_time --;
}

//按键处理任务
void TM1650_task(void)
{
    uint8_t down = 0;
    uint8_t key_data = 0;         //按键数值
    //扫描按键
    key_data = TM1650_KEY_Scan(); 

    keydata.sent_flag = 0;
    switch (key_data) 
    {
        case  KEY0_PRES :
        {
            keydata.buff[keydata.cnt] = '0';
            keydata.down_flag[0] = 1;
            down = 1;
        }break;
        case  KEY1_PRES :
        {
            keydata.buff[keydata.cnt] = '1';
            keydata.down_flag[1] = 1;
            down = 1;
        }break;
        case  KEY2_PRES :
        {
            keydata.buff[keydata.cnt] = '2';
            keydata.down_flag[2] = 1;
            down = 1;
        }break;
        case  KEY3_PRES :
        {
            keydata.buff[keydata.cnt] = '3';
            keydata.down_flag[3] = 1;
            down = 1;
        }break;
        case  KEY4_PRES :
        {
            keydata.buff[keydata.cnt] = '4';
            keydata.down_flag[4] = 1;
            down = 1;
        }break;
        case  KEY5_PRES :
        {
            keydata.buff[keydata.cnt] = '5';
            keydata.down_flag[5] = 1;
            down = 1;
        }break;
        case  KEY6_PRES :
        {
            keydata.buff[keydata.cnt] = '6';
            keydata.down_flag[6] = 1;
            down = 1;
        }break;
        case  KEY7_PRES :
        {
            keydata.buff[keydata.cnt] = '7';
            keydata.down_flag[7] = 1;
            down = 1;
        }break;
        case  KEY8_PRES :
        {
            keydata.buff[keydata.cnt] = '8';
            keydata.down_flag[8] = 1;
            down = 1;
        }break;
        case  KEY9_PRES :
        {
            keydata.buff[keydata.cnt] = '9';
            keydata.down_flag[9] = 1;
            down = 1;
        }break;
        case  KEY_ENTER :
        case  KEY_CANCEL :
        {
            keydata.sent_flag = 1;
            down = 1;
        }break;
    }
    //按键数值有变化
    if( key_copy != key_data )
    {   

       if(down ){
            //有按键按下
            if( keydata.sent_flag )
            {
                //发送数据 
                Rs485_Addr_Scan();              //扫描拨码开关
                usart_send_key_buff(rs485_addr,keydata.cnt,keydata.buff); 
                keydata.sent_flag = 0;
                keydata.down_time = 0;
                keydata.time_out_flag = 1;
                keydata.cnt = 0 ;
                memset(keydata.buff,'0',20);       //清除按键缓存
            }else{
                if( ++keydata.cnt >= 19 )
                       keydata.cnt = 19;
                keydata.time_out_flag = 0;
                keydata.down_time = KEY_DOWN_TIME;  //重新开始计算时间
            }
          down = 0;
          Beep_time_set(10,1);                 //按键按下 短叫一下
          LL_mDelay(100);
       }
       key_copy = key_data;
    }
    if( keydata.down_time == 0 && keydata.time_out_flag == 0 ) 
    {
       down = 0;
       keydata.cnt = 0 ;
       keydata.time_out_flag = 1;
       Beep_time_set(50,1);               //按键按下 长叫一下 
       memset(keydata.buff,'0',20);       //清除按键缓存
    }
    else if( keydata.scan_time == 0 && keydata.down_time == 0)
    {   
        //定时初始化打开芯片。防止芯片不稳定而无法继续识别按键
        keydata.scan_time = 1000;
        //重新初始化TM1650芯片
        TM1650_cfg_display(PARAMETER_BRIGHTNESS_SEVEN|0x01);
        TM1650_clear();
    }

}


/************************ (C) COPYRIGHT Xinling *****END OF FILE****/
